//闭包



///函数作为返回值
////高阶函数既可以接受函数作为参数外，还可以作为结果返回一个值

//通常对一个求和函数是这样子定义的
var arr=[1,2,3,4,5]
function sum(arr){
    return arr.reduce(function(x,y){
        return x+y
    })
}
console.log(sum(arr));  //15

///不需要立即求和，返回求和的函数
var a=[1,2,3,4,5,6]
function sum1(a){
    var sum2=function(){
        return a.reduce(function(x,y){
            return x+y
        })
    }
    return sum2
}
var a1=sum1(a)
console.log(sum1(a));  //返回求和函数
///求和
console.log(a1());   //21
////////在这个例子里，sum1里又定义了一个sum2，并且，内部函数sum2可以引用外部函数sum1的参数和变量，当sum1返回sum2时，相关参数和变量都保留在返回的函数中，称为闭包
///////当在调用sum1函数时，每次返回都会是一个新的函数，即使传入的参数是一样的，但仍互不影响
var f1=sum1(a);
var f2=sum1(a);
console.log(f1===f2);  //false 

///返回的函数并没有被立即执行，而是调用到了fn()才执行
function count(){
    let arr=[]
    for (var index = 1; index <= 3; index++) {
        arr.push(function(){
            return index * index
        })     
    }
    //console.log(index);  //输出的是4
    return arr;
}
let fn=count()
let fn1=fn[0]
let fn2=fn[1]
let fn3=fn[2]
console.log(fn1());  //由于上面输出的是4，所以输出16
console.log(fn2());  //16
console.log(fn3());  //16
///全是16，原因是返回时引用了变量index，但他并没有立即执行，待三个函数都返回时，引用的变量i已经变成了4，所以为16
//返回闭包：返回函数时不要引用任何循环变量，或者后者会发生改变的变量

//若一定要用循环执行，则需再创建一个函数，用该函数的参数绑定循环变量当前的值，无论后续循环变量怎么改变，已绑定的参数不会发生任何改变
function count1(){
    let arr1=[]
    for (let index = 1; index <= 3; index++) {
        arr1.push((function(n){
            return function(){
                return n * n
            }
        })(index));
    }
    return arr1;
}
let ab=count1()
let ab1=ab[0]
let ab2=ab[1]
let ab3=ab[2]
console.log(ab1());  //1
console.log(ab2());  //4
console.log(ab3());  //9



//借助闭包，可以封装一个私有变量，如创建一个计数器
function jishuqi(js){
    var x=js || 0
    return{
        inc:function () {
             x += 1;
            return x;
        }
    }
}
var c1=jishuqi()
console.log(c1.inc());  //1
console.log(c1.inc());  //2
console.log(c1.inc());  //3

var c2=jishuqi(10)
console.log(c2.inc());  //11
console.log(c2.inc());  //12
console.log(c2.inc());  //13

//闭包还可以把多参数的函数变成单参数的函数
//例如，要计算xy可以用Math.pow(x, y)函数，不过考虑到经常计算x2或x3，我们可以利用闭包创建新的函数pow1和pow2：
function zhishu(n) {
    return function (x) {
        return Math.pow(x,n)  //n为指数，即平方立方
    }
}
let pow1=zhishu(2)  //创建新的函数来定义n
let pow2=zhishu(3)
console.log(pow1(10));  //10的平方
console.log(pow1(20));  //20的平方
console.log(pow2(10));  //10的立方
console.log(pow2(20));  //20的立法



////////脑洞大开
